package ndquangr.intern.ringtonemaker;


import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.provider.MediaStore;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;

public class EditAudioActivity extends Activity {
	/** Load lame library for mp3 encode */
	
	
	
	/** Global variables */
	private Context m_context;
	private ContentResolver mCr;

	
	private Bitmap m_graph;
	private int displayWidth, displayHeight;
	private float graph_current_x, graph_current_y;
	private int graph_scrollByX;
	private int graph_realPos, start_realPos, end_realPos;
	private int img_width, img_height;
	
	private int GRAPH_HEIGHT;
	
	/** Control variables */
	private ImageView img_graph;
	private ImageView img_selection;
	private ImageView img_pointer;
	private ImageView img_selection_start;
	private ImageView img_selection_end;
	private ImageView btn_play;
	private ImageView btn_start;
	private ImageView btn_end;
	private ImageView btn_apply;
	private ImageView btn_save;
	private ImageView btn_close;	
	private Drawable slider;
	private FrameLayout flayout;
	private ProgressDialog progDailog;
	
	short [] data; // Data cheap read for every 10ms
	WavIO waveFile;
	NativeMP3Decoder mp3Decoder;
	
	//public static int MAX_SAMPLES = 50000;
	private MediaPlayer mp = new MediaPlayer();
	private String filePath;
	private int fileDuration;
	private FILE_TYPE filetype;
	// Initialization	
	public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.edit_audio_layout);
        m_context = this;
        mCr = getContentResolver();
        
		// Get information from intent
        Bundle extras = getIntent().getExtras();
		if (extras != null) {	
			progDailog = ProgressDialog.show(m_context,
					"Processing audio file", "Please wait....",
					true);
			
			// Get specific songs base on tag
			filePath = extras.getString("uri");
			
			new Thread() {
				public void run() {
					try{					
						// Set up media player
						initializeMediaPlayer(filePath);
						
						// Read audio file data
						data = new short [fileDuration/10];
						if (filePath != null && filePath.endsWith(".wav")) {
							filetype = FILE_TYPE.WAV;
							readPCM(filePath);		
							
						} else {
							filetype = FILE_TYPE.MP3;
							readMP3(filePath);
						}						
					} catch (Exception e) { }
					Message msg = new Message();
					msg.what = 0;
					handler.sendMessage(msg);
					progDailog.dismiss(); 
					}
				}.start();
		}		        
	}

	String newFileNameFromDialog;
	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == 0) {
				setContentView(R.layout.edit_audio_layout);		
				// Get global values
			    Display display = ((WindowManager)
		        getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
	
			    displayWidth = display.getWidth();             
			    displayHeight = display.getHeight();
			    graph_realPos = 0; 
			    start_realPos = 0; 
			    end_realPos = 100;
			    start_rect = new Rect();
			    end_rect = new Rect();
			    GRAPH_HEIGHT = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics());
			    
			    // Get all control instances
				getControlInstances();
				
				// Add action listener for controls
		        addActionListener(); 
				
				// Initialize view for graph of audio data
		        initializeGraph();
			} else if (msg.what == 1) {
				// Save file
				newFileNameFromDialog = msg.obj.toString();
				
				// Show progress dialog			
				progDailog = ProgressDialog.show(m_context,
						"Saving audio file", "Please wait....",
						true);
				
				// Start a thread to save to a new file			
				new Thread() {
					public void run() {
						String newFilePath;
						if (newFileNameFromDialog == null || newFileNameFromDialog == "") {
							newFileNameFromDialog = "my ringtone";
						}
						File root = new File(Environment.getExternalStorageDirectory(), "My tones");
			            if (!root.exists()) {
			                root.mkdirs();
			            }
						if (filetype.equals(FILE_TYPE.WAV)) {
							// Save to new file
							newFilePath = root.getAbsolutePath() +"/" + newFileNameFromDialog + ".wav"; 
							boolean fileSaveResult = waveFile.save(start_realPos*100, end_realPos*100, newFilePath);
							
							// Add metadata to new file
							if (fileSaveResult) {
								ContentValues values = new ContentValues();
								values.put(MediaStore.MediaColumns.DATA, newFilePath);
								values.put(MediaStore.MediaColumns.TITLE, newFileNameFromDialog);
								values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/wav");
								values.put(MediaStore.MediaColumns.SIZE, (end_realPos - start_realPos)*100 );
								values.put(MediaStore.Audio.Media.ARTIST, R.string.app_name);
								values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
								values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
								values.put(MediaStore.Audio.Media.IS_ALARM, true);
								values.put(MediaStore.Audio.Media.IS_MUSIC, true);
								
								Uri uri = MediaStore.Audio.Media.getContentUriForPath(newFilePath);
							    mCr.delete(uri, MediaStore.MediaColumns.DATA + "=\"" + newFilePath + "\"", null);
							    mCr.insert(uri, values);
							}
						} else if (filetype.equals(FILE_TYPE.MP3)) {
							
						}
						
						//handler.sendEmptyMessage(0);
						progDailog.dismiss(); 
						}
					}.start();		
				
			}
		}
	};
		
	private void initializeMediaPlayer(String fileName) {
		try {
			//descriptor = m_context.getAssets().openNonAssetFd(fileName);
			mp.reset();
		    //mp.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
			mp.setDataSource(fileName);
		    mp.prepare();
		    fileDuration = mp.getDuration();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	    
	}
	
	/*
	 * Get view control instances
	 */
	private void getControlInstances() {
		img_graph = (ImageView) findViewById(R.id.img_audioEdit_graph);
		img_selection = (ImageView) findViewById(R.id.img_audioEdit_selection);
		img_selection_start = (ImageView) findViewById(R.id.img_audioEdit_startTime);
		img_selection_end = (ImageView) findViewById(R.id.img_audioEdit_endTime);
		img_pointer = (ImageView) findViewById(R.id.img_audioEdit_pointer);
		
		img_height = img_graph.getLayoutParams().height;	
		flayout = (FrameLayout) findViewById(R.id.fl_audioEdit);
		btn_play = (ImageView) findViewById(R.id.btn_editAudio_play);
		btn_save = (ImageView) findViewById(R.id.btn_editAudio_save);
	}

	/*
	 * Add action listeners to controls
	 */
	private void addActionListener() {
		img_graph.setOnTouchListener(graphTouchEvent);
		img_selection_start.setOnTouchListener(startSelectionTouchEvent);
		img_selection_end.setOnTouchListener(endSelectionTouchEvent);
		btn_play.setOnClickListener(playButtonClickListener);
		btn_save.setOnClickListener(saveButtonClickListener);
	}

	/*
	 * Initialize audio data graph
	 */
	private void initializeGraph() {		
		m_graph = Bitmap.createBitmap(data.length/10, (int)Math.floor(GRAPH_HEIGHT), Bitmap.Config.ARGB_8888);
        createGraph(m_graph);

		//m_graph = BitmapFactory.decodeResource(getResources(), R.drawable.landscape);
		img_width = m_graph.getWidth();
		img_height = m_graph.getHeight();
		
		// Set up ImageView for graph
		img_graph.setImageBitmap(m_graph);
        
        slider = getResources().getDrawable(R.drawable.slider);
        
        img_selection_start.setImageDrawable(slider);
        img_selection_end.setImageDrawable(slider);
        img_selection_start.scrollTo(-start_realPos + slider.getIntrinsicWidth()/2, 0);
        img_selection_end.scrollTo(-end_realPos + slider.getIntrinsicWidth()/2, 0);
        
        drawSelectionRegion(start_realPos, end_realPos);
	}

	/*
	 * Generate graph (wave form) from audio data
	 */
	private void createGraph(Bitmap bitmap) {
		// TODO Auto-generated method stub
		Canvas canvas = new Canvas(bitmap);
		int y_scale;
		if(filetype.equals(FILE_TYPE.WAV)) {
			y_scale = 128;			
		} else {
			y_scale = 8;			
		}
        
        final int color = Color.BLUE; 
        final Paint paint = new Paint();
        paint.setColor(color);
        
        float cur_point_x, cur_point_y;
        float next_point_x, next_point_y;


        int i = 1;
        next_point_x = 0;
        next_point_y = -data[0]/y_scale + GRAPH_HEIGHT/2;
        while(i<data.length) {
                cur_point_x = next_point_x;
                cur_point_y = next_point_y;
                next_point_x = i/10;
            next_point_y = -data[i]/y_scale + GRAPH_HEIGHT/2;
            canvas.drawLines(new float [] {cur_point_x, cur_point_y, next_point_x, 
                        next_point_y}, paint);
            i++;
        }

        int label_steps = fileDuration/15000;
        int sec, min;
        sec = 0; min = 0;
        String text;
        paint.setColor(Color.WHITE);
        //paint.setTextSize(10);
        for (i=1;i<label_steps;i++) {
        	sec += 15;
        	if (sec == 60) {
        		min++;
        		sec = 0;
        	}
        	text = "0" + min + ":" + sec;
        	if (sec == 0) {
        		text = text + "0";
        	}
        	canvas.drawText(text, i*150, 10, paint);
        }
        if (label_steps == 0) {
        	canvas.drawText("00:15", 150, 10, paint);
        }
	}

	/*
	 * Draw selection region
	 */
	private void drawSelectionRegion(int start, int end) {
		// TODO Auto-generated method stub
		if (end < 0 || start > displayWidth) {
			img_selection.setImageBitmap(null);
		} else {
			if (start < 0) {
				start = 0;
			} else if (end > displayWidth) {
				end = displayWidth;
			}
			Bitmap b = Bitmap.createBitmap(displayWidth, img_height, Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(b);
						
			Rect r = new Rect(start, 0, end, img_height);
			Paint paint = new Paint();
			paint.setStyle(Paint.Style.FILL);
			paint.setColor(Color.CYAN);			
			paint.setAlpha(100);
			canvas.drawRect(r, paint);
			
			img_selection.setImageBitmap(b);
		}
		
		img_selection.refreshDrawableState();
		//img_selection.invalidate();
	}	

	/*
	 * Decode Mp3 files
	 */
	private void readMP3(String path) {
		// TODO Auto-generated method stub
		mp3Decoder = new NativeMP3Decoder(path);
		if (mp3Decoder.getHandle() != -1) {			
			mp3Decoder.readCheapSamples(data);
		}
	}

	/*
	 * Read wav file
	 */
	private void readPCM(String path) {
		// TODO Auto-generated method stub
		waveFile = new WavIO(path);
		String sbody = "";
		if (!waveFile.read(data)){			
			// Inform user
		}
		
	}
	
	/*
	 * Action listeners for images
	 */
	private int real_scroll;
	// Action listener for touch event on graph
	private OnTouchListener graphTouchEvent = new OnTouchListener() {
		
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			float curX, curY;
			
            switch (event.getAction()) {
            	
                case MotionEvent.ACTION_DOWN:
                    graph_current_x = event.getX();
                    graph_current_y = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    curX = event.getX();
                    curY = event.getY();
                    graph_scrollByX = (int) (graph_current_x - curX);
                    if ((graph_realPos + graph_scrollByX) < 0) {
                    	real_scroll = -graph_realPos;
                    	graph_realPos = 0;
                    }
                    else if ((graph_realPos + graph_scrollByX) > (img_width - displayWidth)) {
                    	real_scroll = img_width - displayWidth - graph_realPos;
                    	graph_realPos = img_width - displayWidth;
                    } else {  
                    	real_scroll = graph_scrollByX;                    	
                    	graph_realPos+= graph_scrollByX;
                    }

                    // Scroll graph and also the sliders
                	img_graph.scrollBy(real_scroll, 0);
                	img_selection_start.scrollBy(real_scroll, 0);
                	img_selection_end.scrollBy(real_scroll, 0);
                	prepareRedrawSelectionRegion();
                	
                    graph_current_x = curX;
                	graph_current_y = curY;
                    break;
                    
                case MotionEvent.ACTION_UP:
                	curX = event.getX();
                    curY = event.getY();
                    graph_scrollByX = (int) (graph_current_x - curX);
                    if ((graph_realPos + graph_scrollByX) < 0) {
                    	real_scroll = -graph_realPos;
                    	graph_realPos = 0;
                    }
                    else if ((graph_realPos + graph_scrollByX) > (img_width - displayWidth)) {
                    	real_scroll = img_width - displayWidth - graph_realPos;
                    	graph_realPos = img_width - displayWidth;
                    } else {  
                    	real_scroll = graph_scrollByX;                    	
                    	graph_realPos+= graph_scrollByX;
                    }

                    // Scroll graph and also the sliders
                	img_graph.scrollBy(real_scroll, 0);
                	img_selection_start.scrollBy(real_scroll, 0);
                	img_selection_end.scrollBy(real_scroll, 0);
                	prepareRedrawSelectionRegion();
                    break;
            }

            return true;
		}
	};
	
	float start_current_x, start_current_y;
	int start_scroll_by_x;
	Rect start_rect, end_rect;
	// Action listener for touch event on graph
	private OnTouchListener startSelectionTouchEvent = new OnTouchListener() {
		
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			float curX, curY;
			
            switch (event.getAction()) {
            	
                case MotionEvent.ACTION_DOWN:
                	start_current_x = event.getX();
                	start_current_y = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    curX = event.getX();
                    curY = event.getY();
                    start_scroll_by_x = (int) (start_current_x - curX);
                    start_realPos -= start_scroll_by_x;
                    end_realPos -= start_scroll_by_x;
                    
                    // Scroll two sliders
                    img_selection_start.scrollBy(start_scroll_by_x, 0);
                    img_selection_end.scrollBy(start_scroll_by_x, 0);                
                    prepareRedrawSelectionRegion();
                    
                    start_current_x = curX;
                    start_current_y = curY;
                    break;
                    
                case MotionEvent.ACTION_UP:
                	curX = event.getX();
                    curY = event.getY();
                    start_scroll_by_x = (int) (start_current_x - curX);
                    start_realPos -= start_scroll_by_x;
                    end_realPos -= start_scroll_by_x;
                    
                    // Scroll two sliders
                    img_selection_start.scrollBy(start_scroll_by_x, 0);
                    img_selection_end.scrollBy(start_scroll_by_x, 0);
                    prepareRedrawSelectionRegion();
                    
                    break;
            }

            return true;
		}
	};
	
	float end_current_x, end_current_y;
	int end_scroll_by_x;
	// Action listener for touch event on graph
	private OnTouchListener endSelectionTouchEvent = new OnTouchListener() {
		
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			float curX, curY;
			
            switch (event.getAction()) {
            	
                case MotionEvent.ACTION_DOWN:
                	end_current_x = event.getX();
                	end_current_y = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    curX = event.getX();
                    curY = event.getY();
                    end_scroll_by_x = (int) (end_current_x - curX);
                   
                    end_realPos -= end_scroll_by_x;
                    
                    img_selection_end.scrollBy(end_scroll_by_x, 0);
                    prepareRedrawSelectionRegion();
                    end_current_x = curX;
                    end_current_y = curY;
                    break;
                    
                case MotionEvent.ACTION_UP:
                	curX = event.getX();
                    curY = event.getY();
                    end_scroll_by_x = (int) (end_current_x - curX);
                    end_realPos -= end_scroll_by_x;
                    
                    img_selection_end.scrollBy(end_scroll_by_x, 0);
                    prepareRedrawSelectionRegion();
                    
                    break;
            }

            return true;
		}
		
	};
	
	private OnClickListener playButtonClickListener = new OnClickListener() {		
		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			mp.seekTo(start_realPos*100);
			mp.start();
			handler.post(playingProgressCheck);
		}
	};
	
	/*
	 * Save audio file in specific start and end time to wav file
	 */
	private OnClickListener saveButtonClickListener = new OnClickListener() {
				
		@Override
		public void onClick(View v) {
			
			// Require user input new file name
			LayoutInflater li = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			View dialogView = li.inflate(R.layout.get_filename_dialog, null);

			//Button okButton = (Button) dialogView.findViewById(R.id.btn_filenameDialog_ok);
			final EditText edtFileName = (EditText)dialogView.findViewById(R.id.edt_filenameDialog_filename);

			AlertDialog filenameDialog = new AlertDialog.Builder(m_context)
			    .setTitle("Enter the Zip Code")
			    .setView(dialogView)
			    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
			        public void onClick(DialogInterface dialog, int whichButton) {
			        	String filename = edtFileName.getText().toString();
			        	Message msg = new Message();
			        	msg.obj = filename;
			        	msg.what = 1;
			        	msg.setTarget(handler);			        	
			        	msg.sendToTarget();
			        }
			    }).create();
			filenameDialog.show();

			/*
			// Show progress dialog			
			progDailog = ProgressDialog.show(m_context,
					"Saving audio file", "Please wait....",
					true);
			
			// Start a thread to save to a new file			
			new Thread() {
				public void run() {
					String newFilePath;
					if (newFileNameFromDialog == null || newFileNameFromDialog == "") {
						newFileNameFromDialog = "my ringtone";
					}
					File root = new File(Environment.getExternalStorageDirectory(), "My tones");
		            if (!root.exists()) {
		                root.mkdirs();
		            }
					if (filetype.equals(FILE_TYPE.WAV)) {
						// Save to new file
						newFilePath = root.getAbsolutePath() +"/" + newFileNameFromDialog + ".wav"; 
						boolean fileSaveResult = waveFile.save(start_realPos*100, end_realPos*100, newFilePath);
						
						// Add metadata to new file
						if (fileSaveResult) {
							ContentValues values = new ContentValues();
							values.put(MediaStore.MediaColumns.DATA, newFilePath);
							values.put(MediaStore.MediaColumns.TITLE, newFileNameFromDialog);
							values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/wav");
							values.put(MediaStore.MediaColumns.SIZE, (end_realPos - start_realPos)*100 );
							values.put(MediaStore.Audio.Media.ARTIST, R.string.app_name);
							values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
							values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
							values.put(MediaStore.Audio.Media.IS_ALARM, true);
							values.put(MediaStore.Audio.Media.IS_MUSIC, true);
							
							Uri uri = MediaStore.Audio.Media.getContentUriForPath(newFilePath);
						    mCr.delete(uri, MediaStore.MediaColumns.DATA + "=\"" + newFilePath + "\"", null);
						    mCr.insert(uri, values);
						}
					}
					handler.sendEmptyMessage(0);
					progDailog.dismiss(); 
					}
				}.start();		
			*/
		}
	};
	
	/**
	 * This is used for update seek bar progress and set the current played time in text view 
	 */
	private Runnable playingProgressCheck = new Runnable(){
		@Override
		public void run() {
			if (mp == null)
			{
				return;
			}
			int position = mp.getCurrentPosition();
			if(position % 100 == 0) {
				drawPointer(position/100-graph_realPos);
			}
			if (position >= end_realPos*100) {
				mp.pause();
			}
			//playingStatus.setProgress(position);
			//tv_progress.setText(stringForTime(position));
			handler.post(playingProgressCheck);
		}		
	};
	
	private void prepareRedrawSelectionRegion() {
		//img_selection_start.getDrawingRect(start_rect);
		//img_selection_end.getDrawingRect(end_rect);
		//drawSelectionRegion(start_rect.left, end_rect.left);
		drawSelectionRegion(start_realPos - graph_realPos, end_realPos - graph_realPos);
	}
	
	private void drawPointer(int position) {
		// TODO Auto-generated method stub
		if(position < 0 || position > displayWidth) {
			img_pointer.setImageBitmap(null);
			
		} else {
			Bitmap b = Bitmap.createBitmap(displayWidth, img_height, Bitmap.Config.ARGB_8888);
			Canvas canvas = new Canvas(b);
			Paint paint = new Paint();
			paint.setStyle(Paint.Style.STROKE);
			paint.setColor(Color.YELLOW);			
			paint.setPathEffect(new DashPathEffect(new float[] {5,5}, 0));
			canvas.drawLine(position, 0, position, img_height, paint);
			
			img_pointer.setImageBitmap(b);
		}
	
		img_pointer.refreshDrawableState();
	}
}
